package sunyu.kit.common;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.*;

/**
 * 线程工具类
 * <p>
 * 应用程序执行完毕后，需要调用destroy方法
 *
 * @author 孙宇
 */
public class ExecutorServiceKit {

    private static final Logger logger = LogKit.getLogger();

    private static ExecutorService executorService = null;

    private static int poolSize = Runtime.getRuntime().availableProcessors() * 2;

    static {
        logger.info("初始化线程池开始");

        //setPoolSize();

        executorService = Executors.newFixedThreadPool(getPoolSize());

        logger.info("初始化的线程池大小：{}", getPoolSize());

        logger.info("初始化线程池结束");
    }

    /**
     * 根据 Java 虚拟机可用处理器数目返回最佳的线程数。<br>
     * 最佳的线程数 = CPU可用核心数 / (1 - 阻塞系数)，其中阻塞系数这里设为0.9
     */
    private static void setPoolSize() {
        try {
            destroy();
            // JVM可用处理器的个数
            final int cores = Runtime.getRuntime().availableProcessors();
            logger.info("JVM可用处理器的个数：{}", cores);
            // 最佳的线程数 = CPU可用核心数 / (1 - 阻塞系数)
            // 阻塞系数是不是需要有个setter方法能让使用者自由设置呢？
            logger.info("最佳的线程数 = CPU可用核心数 / (1 - 阻塞系数)");
            logger.info("最佳的线程数 = {} / (1 - {})", cores, 0.9);
            poolSize = (int) (cores / (1 - 0.9));
        } catch (Throwable e) {
            logger.error(ExceptionUtils.getStackTrace(e));
        }
    }

    /**
     * 应用程序执行完毕后，一定要调用这个方法
     */
    public static void destroy() {
        if (executorService != null && !executorService.isShutdown()) {
            logger.info("销毁线程池开始");
            executorService.shutdown();
            logger.info("销毁线程池结束");
        }
    }

    /**
     * 使用线程执行一个runnable
     *
     * @param runnable
     */
    public static void execute(Runnable runnable) {
        if (executorService != null) {
            executorService.execute(runnable);
        }
    }

    /**
     * 执行一个回调
     *
     * @param callback
     * @return
     */
    public static Future submit(Callable callback) {
        if (executorService != null) {
            return executorService.submit(callback);
        }
        return null;
    }

    /**
     * 获得线程池大小
     *
     * @return
     */
    public static int getPoolSize() {
        return poolSize;
    }

    /**
     * 自定义线程池大小
     *
     * @param size
     */
    public static void setPoolSize(int size) {
        destroy();
        poolSize = size;
        executorService = Executors.newFixedThreadPool(getPoolSize());
        logger.info("线程池大小更改为：{}", getPoolSize());
    }

    /**
     * 等待一批结果
     *
     * @param futureList
     * @return
     */
    public static List waitResults(Collection<Future> futureList) {
        List resultList = new ArrayList();
        waitResults(futureList, resultList);
        return resultList;
    }

    /**
     * 等待一批结果，并将结果存入resultList返回
     *
     * @param futureList
     * @param resultList
     */
    public static void waitResults(Collection<Future> futureList,
                                   Collection resultList) {
        for (Future f : futureList) {
            if (f != null) {
                try {
                    resultList.add(f.get());
                } catch (InterruptedException e) {
                    logger.error(ExceptionUtils.getStackTrace(e));
                } catch (ExecutionException e) {
                    logger.error(ExceptionUtils.getStackTrace(e));
                }
            }
        }
    }

    /**
     * 判断所有线程是否执行完毕
     * <p>
     * 注意：判断后，需要重新调用setPoolSize(n)才能继续使用线程工具
     *
     * @return
     */
    public static boolean isTerminated() {
        if (executorService != null) {
            if (!executorService.isShutdown()) {
                executorService.shutdown();
            }
            return executorService.isTerminated();
        }
        return true;
    }

}
